//
//  MantisGCDHandle.m
//  Runner
//
//  Created by iosdeveloper on 2020/8/30.
//  Copyright © 2020 The Chromium Authors. All rights reserved.
//

#import "MantisGCDHandle.h"
@interface MantisGCDTool()

@end
@implementation MantisGCDTool
- (instancetype)init{
  if(self = [super init]){
    _maxGroupThreadCount = 4;
  }
  return self;
}

- (NSMutableArray<dispatch_block_t> *)blockContianer{
    if(!_blockContianer) _blockContianer = [NSMutableArray new];
    return _blockContianer;
}

- (MantisGCDHandlerBlock)execute{
    
    MantisGCDHandlerBlock block = ^MantisGCDTool*(dispatch_block_t _task){
        if(!_task) return self;
        if(_isGroup||!_isAsync){//如果分组 先存起来，最后执行
            [self.blockContianer addObject:_task];
        }else{ //如果不分组，直接执行
            [MantisGCDTool backgroundBlock:_task];
        }
        return  self;
    };
    return block;
}

- (MantisGCDTool *)executeInMain:(dispatch_block_t)task{
    dispatch_block_t mainTask = ^(){
        [MantisGCDTool mainBlock:^{
            if(task) task();
        }];
    };
    return [self execute](mainTask);
}

- (MantisGCDTool *)executeInBackground:(dispatch_block_t)task{
    dispatch_block_t backgroundTask = ^(){
        [MantisGCDTool backgroundBlock:^{
            if(task) task();
        }];
    };
    return [self execute](backgroundTask);
}

- (MantisGCDTool *)groupAsyncWithFinishedBlock:(dispatch_block_t)finish{
    finish = ^(){
        _isGroup = false;
        [_blockContianer removeAllObjects];
        if(finish) finish();
    };
    [MantisGCDTool batchTaskWithAllCount:(int)self.blockContianer.count maxConcurrent:_maxGroupThreadCount task:self.blockContianer finished:finish];
    return self;
}

- (void)end:(dispatch_block_t)finish{
    //group模式
    if(_isGroup){
        [self groupAsyncWithFinishedBlock:finish];
        return ;
    }
    //子线程开辟同步任务模式
    if(!_isAsync){
        [MantisGCDTool syncBlock:^{
            for (dispatch_block_t block in self.blockContianer) {
                block();
            }
        }];
    }
    return ;
}


+ (void)mainBlock:(dispatch_block_t)task{
    BOOL isMainThread = [[NSThread currentThread] isMainThread];
    if(isMainThread){
        task();
        return;
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        if(task) task();
    });
}

+ (void)backgroundBlock:(dispatch_block_t)task{
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        if(task) task();
    });
}

+ (void)syncBlock:(dispatch_block_t)block{
    dispatch_queue_t queue = dispatch_queue_create("sync", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        if(block) block();
    });
}

+ (void)batchTaskWithAllCount:(int)taskCount
                maxConcurrent:(int)maxConcurrent
                         task:(NSArray<dispatch_block_t> *)tasks
                     finished:(dispatch_block_t)finished{
    dispatch_group_t group = dispatch_group_create();
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(maxConcurrent);
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    for (int i = 0; i < taskCount; i++)
    {
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        //注意这里信号量从maxConcurrent开始递减,并不会阻塞循环.循环maxConcurrent次,递减到0的时候,开始阻塞.
        dispatch_group_async(group, queue, ^{
            dispatch_block_t task;
            if(i>tasks.count-1) {
                task = tasks.lastObject;
            }else{
                task = tasks[i];
            }//必须保证queue在task 完成之后再调用
          dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
            dispatch_sync(queue, ^{
              if(task) task();
              dispatch_semaphore_signal(semaphore);
            });
        });//创建一个新线程,并在线程结束后,发送信号量,通知阻塞的循环继续创建新线程.
    }
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        if(finished) finished();
    });
}

@end

@interface MantisGCDHandle()

@end
@implementation MantisGCDHandle

+ (instancetype)defaultHandler{
  static MantisGCDHandle * handler;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
    handler = [MantisGCDHandle new];
  });
  return handler;
}


- (MantisGCDTool *)async{
  MantisGCDTool * tool = [MantisGCDTool new];
  tool.isAsync = YES;
  return tool;
}

- (MantisGCDTool *)sync{
  MantisGCDTool * tool = [MantisGCDTool new];
  tool.isAsync = NO;
  return tool;
}

- (MantisGCDTool *)groupAsync{
  MantisGCDTool * tool = [MantisGCDTool new];
  tool.isGroup = YES;
  return tool;
}


@end
